﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;

namespace MISTBowl_Brackets
{
	class MainClass
	{
		static string originalTitle = Console.Title;
		static string fileName = string.Empty;
		static List<Team> teamsList = new List<Team>();
		static List<Team> origTeamsList = new List<Team>();
		static string roundName = string.Empty;
		static string LastFixtures;
		static List<List<Team>> combinations = new List<List<Team>>();


		public static int Main()
		{
			try
			{
				Console.BackgroundColor = ConsoleColor.DarkBlue;
				Console.ForegroundColor = ConsoleColor.White;
				Console.Title = "MIST Bowl Bracket Software";
				Clear();
				while (true)
				{
					Console.WriteLine("Press [c] to create a new tournament file, [e] to use an existing one, or [q] to quit.");
					char option = Console.ReadKey(true).KeyChar;
					Console.WriteLine();
					if (option == 'c')
					{
						Console.WriteLine("OK, creating new file. . .");
						do
							fileName = GetNewFileName();
						while (File.Exists(fileName) || Directory.Exists(fileName));
						break;
					}
					if (option == 'e')
					{
						Console.WriteLine("OK, using existing file. . .");
						fileName = GetExistingFileName();
						break;
					}
					if (option == 'q')
						return 0;
					Console.WriteLine("Invalid option '" + option + "'.");
				}
				Clear();
				if (!File.Exists(fileName))
				{
					Console.WriteLine("For each team participating in the MIST Bowl tournament, please type the team ID, followed by a comma, followed by the team's region name, like as follows:");
					Console.ForegroundColor = ConsoleColor.Green;
					Console.WriteLine("1000,Detroit");
					Console.WriteLine("1100/1600,Toronto");
					Console.ForegroundColor = ConsoleColor.Magenta;
					Console.WriteLine("MAKE SURE ALL REGION NAMES ARE SPELLED CORRECTLY!");
					Console.ForegroundColor = ConsoleColor.White;
					Console.WriteLine("Press [Enter] twice when finished.");
					Console.WriteLine();
					while (true)
					{
						var s = Console.ReadLine().ToUpper();
						if (s == string.Empty)
							break;
						if (!Regex.IsMatch(s, "^[0-9]+(/[0-9]+)* *, *[^ ,][^,]*$") || s.Split('/').Any(a => teamsList.Any(b => b.teamId.Split('/').Contains(a))))
							throw new InvalidDataException();
						teamsList.Add(new Team(Regex.Replace(s, " *, *", ",").Split(',')));
					}
					if (teamsList.ToArray().Length == 0)
						throw new InvalidDataException();
					origTeamsList = teamsList.ToList();
					Clear();
					WriteToFile();
				}
				Console.Write("Please enter the number of preliminary rounds in this tournament: ");
				var prelimRounds = int.Parse(Console.ReadLine());
				for (int i = 0; i < prelimRounds; i++)
				{
					roundName = "PRELIM" + (i + 1) + "/" + prelimRounds;
					Clear();
					Console.WriteLine("Please list below the teams in each match during this preliminary round, like as follows:");
					Console.ForegroundColor = ConsoleColor.Green;
					Console.WriteLine("1000,1100/1600,2000");
					Console.WriteLine("3000,3300,3400");
					Console.ForegroundColor = ConsoleColor.White;
					Console.WriteLine();
					var thisRoundTeams = new List<Team>();
					while (true)
					{
						string s;
						if ((s = Console.ReadLine()) == string.Empty)
							break;
						if (!Regex.IsMatch(s, "^[0-9]+(/[0-9]+)* *(, *[0-9]+(/[0-9]+)* *)+$"))
							throw new InvalidDataException();
						var matchTeams = s.Replace(" ", string.Empty).Split(',').Select(a => teamsList.First(b => b.teamId == a)).ToList();
						if (matchTeams.Any(a => thisRoundTeams.Any(b => b.teamId == a.teamId)))
							throw new InvalidDataException();
						matchTeams.ForEach(a => thisRoundTeams.Add(a));
						Matches.AddMatch(matchTeams.ToArray());
					}
					if (teamsList.Count != thisRoundTeams.Count)
						throw new InvalidDataException();
					Clear();
					Console.WriteLine("Please enter the amount of points earned by each team during this preliminary round.");
					foreach (Team team in teamsList)
					{
						Console.Write(team.teamId + "," + team.region + ": ");
						team.points += int.Parse(Console.ReadLine());
					}
				}
				while (roundName != "F")
				{
					roundName = string.Empty;
					Clear();
					Console.Write("Please enter the number of teams progressing to the next round: ");
					teamsList = teamsList.OrderByDescending(a => a.points).ThenBy(a => TickBasedRandom.GetInteger(int.MinValue, int.MaxValue - 1)).ToList().GetRange(0, int.Parse(Console.ReadLine()) - 1);
					teamsList.ForEach(a => a.points = 0);
					var matchCount = 0;
					while (true)
					{
						Console.Write("Please enter the number of matches taking place in the next round: ");
						try {
							matchCount = int.Parse(Console.ReadLine());
							if (teamsList.Count % matchCount == 0)
								break;
						}
						catch { }
						Console.ForegroundColor = ConsoleColor.Red;
						Console.WriteLine("That is not a valid number of matches given the number of teams. Please try again.");
						Console.ForegroundColor = ConsoleColor.White;
						Console.WriteLine();
					}
					roundName = matchCount == 1 ? "F" : "ROUNDOF" + teamsList.Count;
					Clear();
					Console.WriteLine("The following matches will take place in this round:");
					var matches = Combinations.GenerateBestMatches(teamsList, matchCount / teamsList.Count, matchCount, origTeamsList);
					matches.ForEach(a => Matches.AddMatch(a.ToArray()));
					Console.WriteLine(string.Join(Environment.NewLine, matches.ConvertAll(a => string.Join(" v. ", a.ConvertAll(b => b.teamId)))));
					Console.ForegroundColor = ConsoleColor.Magenta;
					Console.WriteLine("MAKE SURE TO WRITE DOWN THIS MATCH LIST BEFORE CONTINUING.");
					Console.ForegroundColor = ConsoleColor.White;
					Console.WriteLine();
					Console.WriteLine("Press any key to continue. . .");
					System.Threading.Thread.Sleep(3000);
					Console.ReadKey();
					Clear();

					Console.WriteLine("Please enter the amount of points earned by each team.");
					foreach (Team team in teamsList)
					{
						Console.Write(team.teamId + "," + team.region + ": ");
						team.points += int.Parse(Console.ReadLine());
					}
				}
				teamsList = teamsList.OrderByDescending(a => a.points).ThenBy(a => TickBasedRandom.GetInteger(int.MinValue, int.MaxValue - 1)).ToList();
				Console.WriteLine("1ST PLACE CHAMPIONS: " + teamsList[0].teamId + "," + teamsList[0].region);
				Console.WriteLine("2ND PLACE: " + teamsList[1].teamId + "," + teamsList[1].region);
				Console.WriteLine("3RD PLACE: " + teamsList[2].teamId + "," + teamsList[2].region);
				Console.WriteLine();

				Console.Error.Write("Press any key to quit. . .");
				Console.ReadKey(true);
				Console.Error.WriteLine();
				Console.ResetColor();
				Console.Title = originalTitle;
				return 0;
			}
			catch (Exception e)
			{
				Console.Error.WriteLine();
				Console.Error.WriteLine("Traceback (most recent call last):");
				Console.Error.Write(Traceback.Read());
				Console.Error.WriteLine("\tAt int Main(string[]) (class MainClass):");
				Console.ForegroundColor = ConsoleColor.Red;
				Console.Error.WriteLine("Error: " + e.GetType() + " occurred.");
				Console.Error.WriteLine("Description: " + e.Message);
				Console.ForegroundColor = ConsoleColor.White;
				Console.Error.Write("Press any key to quit. . .");
				Console.ReadKey(true);
				Console.Error.WriteLine();
				Console.ResetColor();
				Console.Title = originalTitle;
				return -1;
			}
		}

		public static string GetNewFileName()
		{
			try
			{
				return GetTempPath() + "MISTBowl_Brackets_" + Path.GetFileNameWithoutExtension(Path.GetRandomFileName()) + ".tmp";
			}
			catch (Exception e)
			{
				Traceback.Write("At string GetNewFileName() (class MainClass):");
				throw e;
			}
		}

		public static string GetExistingFileName()
		{
			try
			{
				var searchResults = Directory.GetFiles(GetTempPath()).ToList();
				if (searchResults.FindIndex(a => Regex.IsMatch(Path.GetFileName(a), "^MISTBowl_Brackets_.*[.]tmp$")) != -1)
					return searchResults.FindAll(a => Regex.IsMatch(Path.GetFileName(a), "^MISTBowl_Brackets_.*[.]tmp$")).OrderByDescending(a => File.GetLastWriteTimeUtc(a).Ticks).ToArray()[0];
				throw new FileNotFoundException();
			}
			catch (Exception e)
			{
				Traceback.Write("At string GetExistingFileName() (class MainClass):");
				throw e;
			}
		}

		public static string GetTempPath()
		{
			try
			{
				var tempPath = Path.GetTempPath();
				if (tempPath == "/tmp/" && Directory.Exists("/var/tmp/"))
					return "/var/tmp/";
				return tempPath;
			}
			catch (Exception e)
			{
				Traceback.Write("At string GetTempPath() (class MainClass);");
				throw e;
			}
		}

		public static void Clear()
		{
			try
			{
				Console.Clear();
				Console.Error.WriteLine("MIST Bowl Bracket Software");
				Console.Error.WriteLine("Copyright (c) 2017 Muhammad Mu'að Imtiaz");
				var maxLength = 40;
				if (teamsList.ToArray().Length > 0)
				{
					maxLength = Math.Max(roundName != string.Empty ? HumanReadableRoundNames.GetHumanReadableName(roundName).Length : 0, Math.Max(40, teamsList.ConvertAll(a => string.Join(",", a).Length).Aggregate((a, b) => Math.Max(a, b))));
					for (int i = 0; i < maxLength; i++)
						Console.Error.Write("-");
					Console.Error.WriteLine();
					Console.Error.WriteLine(string.Join(Environment.NewLine, teamsList.ConvertAll(a => a.teamId + "," + a.region + (teamsList.ConvertAll(b => b.points).Max() != 0 ? "," + a.points.ToString() : string.Empty))));
				}
				if (roundName != string.Empty)
					Console.Error.WriteLine(HumanReadableRoundNames.GetHumanReadableName(roundName));
				for (int i = 0; i < maxLength; i++)
					Console.Error.Write("-");
				Console.Error.WriteLine();
			}
			catch (Exception e)
			{
				Traceback.Write("At void Clear() (class MainClass):");
				throw e;
			}
		}

		public static void WriteToFile()
		{
			try
			{
				using (var fileStream = File.OpenWrite(fileName))
				using (var streamWriter = new StreamWriter(fileStream))
				{
					foreach (Team team in teamsList)
						streamWriter.WriteLine("TEAM:" + team.teamId + "," + team.region);
					if (roundName != string.Empty)
						streamWriter.Write(roundName + ":");
					streamWriter.WriteLine(string.Join(";", teamsList.ConvertAll(a => string.Join(",", a))));
					if (LastFixtures != string.Empty)
					{
						streamWriter.WriteLine("MTCHS:" + LastFixtures);
						LastFixtures = string.Empty;
					}
				}
			}
			catch (Exception e)
			{
				Traceback.Write("At void WriteToFile() (class MainClass):");
				throw e;
			}
		}

		public static void ReadFromFile()
		{
			try
			{
				/*				string text = string.Empty;
								using (var fileStream = File.OpenRead(fileName))
								using (var streamReader = new StreamReader(fileStream))
									text = streamReader.ReadToEnd();
								foreach (string line in Regex.Split(text, Environment.NewLine))
								{
									if (line.StartsWith("TEAM:", StringComparison.Ordinal))
									{
										for(line.Split(':').ToList().GetRange(1, line.Count(a => a == ':'))
									}
									else if (line.Contains(":") && !line.StartsWith("MTCHS:", StringComparison.Ordinal))
										roundName = line.Split(':')[0];
									else if (line.StartsWith("MTCHS:", StringComparison.Ordinal))
										foreach (string match in line.Substring(6).Split(' '))
											Matches.AddMatch(match.Split(' ').ToList().ConvertAll(a => teamsList.First(b => b.teamId == a)).ToArray());

								}*/
				throw new NotImplementedException();
			}
			catch (Exception e)
			{
				Traceback.Write("At void ReadFromFile() (class MainClass):");
				throw e;
			}
		}
	}
}